/*
 * Copyright (c) 2024 HiSilicon Technologies CO., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "pinctrl.h"
#include "pwm.h"
#include "tcxo.h"
#include "soc_osal.h"
#include "app_init.h"
#include "gpio.h"
#include "watchdog.h"
#include "errcode.h"

#define PWM_TASK_PRIO 24
#define PWM_TASK_STACK_SIZE 0x1000

#define CONFIG_PWM_PIN 9
#define CONFIG_PWM_PIN_MODE 1
#define PWM_CHANNEL 1
#define PWM_GROUP_ID 1

#define TEST_TCXO_DELAY_1000MS 1000
#define ONE_TICK_25_NS 25//25ns
#define LONG_TIME_TICKS   22   //550ns
#define SHORT_TIME_TICKS   13   //325ns
//G,R,B三色灯0x00,0xFF,0x00

pwm_config_t cfg_0_no_repeat = {LONG_TIME_TICKS,
                                SHORT_TIME_TICKS,       // 高电平持续tick 时间 = tick * (1/40000000)
                                0,        // 相位偏移位
                                1,        // 发多少个波形
                                true};    // 是否循环

pwm_config_t cfg_1_no_repeat = {SHORT_TIME_TICKS,
                                LONG_TIME_TICKS,       // 高电平持续tick 时间 = tick * (1/40000000)
                                0,        // 相位偏移位
                                1,        // 发多少个波形
                                true};    // 是否循环

// WS2812B颜色结构体
typedef struct {
    uint8_t r, g, b;
} RGBColor;

const RGBColor colors[] = {
    {255,0,0}, {0,255,0}, {0,0,255} // 红绿蓝
};

void SendBit(bool bitVal) {
    uint32_t result = 0;
    //PwmSetDuty(PWM_CHANNEL, bitVal ? 70 : 30); // 高低电平占空比
    //OsalUDelay(bitVal ? 700 : 350);            // 微秒级延时
    if(0!=uapi_pwm_open(PWM_CHANNEL, bitVal ? &cfg_1_no_repeat : &cfg_0_no_repeat))
    {
        osal_printk("\r\n uapi_pwm_open failed!\r\n");
    }
    uint8_t channel_id = PWM_GROUP_ID;
    result = uapi_pwm_set_group(PWM_GROUP_ID, &channel_id, 1);
    // if(0!=result)
    // {
    //     osal_printk("\r\n uapi_pwm_set_group failed!,result is %x\r\n", result);
    // }

    result = uapi_pwm_start(PWM_CHANNEL);
    if(0!=result)
    {
        osal_printk("\r\n uapi_pwm_start failed!,result is %x\r\n", result);
    }
    //uapi_pwm_stop(PWM_CHANNEL);
    result = uapi_pwm_close(PWM_CHANNEL);
    if(0!=result)
    {
        osal_printk("\r\n uapi_pwm_close failed!, result is %x\r\n", result);
    }
}

void SendColor(RGBColor c) {
    for(int i=7; i>=0; i--) SendBit((c.g>>i)&1);
    for(int i=7; i>=0; i--) SendBit((c.r>>i)&1);
    for(int i=7; i>=0; i--) SendBit((c.b>>i)&1);
}

static void *pwm_task(const char *arg)
{
    osal_printk("\r\n\r\n\r\ndemo 000_rgb hello world!\r\n\r\n\r\n");
                // 初始化硬件

    uapi_pin_set_mode(CONFIG_PWM_PIN, CONFIG_PWM_PIN_MODE);
    if(0!=uapi_pwm_init())
    {
        osal_printk("\r\n uapi_pwm_init failed!\r\n");
    }

    UNUSED(arg);

    while (1)
    {
        uapi_watchdog_kick(); // 喂狗，防止程序出现异常系统挂死
    
        while(1) {
            for(int i=0; i<3; i++) {
                SendColor(colors[i]);         // 发送颜色数据
                uapi_tcxo_delay_ms(500);     // SDK提供的毫秒延时
                //SendColor((RGBColor){0,0,0}); // 关闭LED
                //uapi_tcxo_delay_ms(50);
                uapi_gpio_set_val(CONFIG_PWM_PIN, GPIO_LEVEL_LOW);
                osal_udelay(280);
            }
            //uint32_t fre = uapi_pwm_get_frequency(PWM_CHANNEL);
            //osal_printk("\r\nGot pwm frequency:%u\r\n", fre);
        }
    }

    return NULL;
}

static void pwm_entry(void)
{
    osal_task *task_handle = NULL;
    osal_kthread_lock();
    task_handle = osal_kthread_create((osal_kthread_handler)pwm_task, 0, "PwmTask", PWM_TASK_STACK_SIZE);
    if (task_handle != NULL) {
        osal_kthread_set_priority(task_handle, PWM_TASK_PRIO);
        osal_kfree(task_handle);
    }
    osal_kthread_unlock();
}

/* Run the pwm_entry. */
app_run(pwm_entry);